import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TableViewDragSelect extends Application {

    private int startRow = -1;
    private int startCol = -1;

    @Override
    public void start(Stage stage) {
        TableView<Person> tableView = new TableView<>();
        tableView.setEditable(false);
        tableView.getSelectionModel().setCellSelectionEnabled(true);
        tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

        TableColumn<Person, String> nameCol = new TableColumn<>("姓名");
        nameCol.setCellValueFactory(data -> data.getValue().nameProperty());

        TableColumn<Person, String> ageCol = new TableColumn<>("年龄");
        ageCol.setCellValueFactory(data -> data.getValue().ageProperty());

        TableColumn<Person, String> cityCol = new TableColumn<>("城市");
        cityCol.setCellValueFactory(data -> data.getValue().cityProperty());

        tableView.getColumns().addAll(nameCol, ageCol, cityCol);

        tableView.setItems(FXCollections.observableArrayList(
                new Person("张三", "20", "上海"),
                new Person("李四", "21", "北京"),
                new Person("王五", "22", "杭州"),
                new Person("赵六", "23", "南京"),
                new Person("孙七", "24", "苏州")
        ));

        // 鼠标按下：记录起点
        tableView.setOnMousePressed(event -> {
            if (event.getButton() == MouseButton.PRIMARY) {
                TablePosition<?, ?> pos = tableView.getSelectionModel().getSelectedCells().get(0);
                startRow = pos.getRow();
                startCol = pos.getColumn();
                tableView.getSelectionModel().clearSelection();
            }
        });

        // 鼠标拖动：选中矩形区域
        tableView.setOnMouseDragged(event -> {
            if (event.getButton() == MouseButton.PRIMARY && startRow >= 0 && startCol >= 0) {
                TablePosition<?, ?> pos = getCellAtMouse(tableView, event);
                if (pos != null) {
                    int endRow = pos.getRow();
                    int endCol = pos.getColumn();

                    int minRow = Math.min(startRow, endRow);
                    int maxRow = Math.max(startRow, endRow);
                    int minCol = Math.min(startCol, endCol);
                    int maxCol = Math.max(startCol, endCol);

                    tableView.getSelectionModel().clearSelection();
                    for (int row = minRow; row <= maxRow; row++) {
                        for (int col = minCol; col <= maxCol; col++) {
                            tableView.getSelectionModel().select(row, tableView.getColumns().get(col));
                        }
                    }
                }
            }
        });

        VBox root = new VBox(tableView);
        Scene scene = new Scene(root, 600, 400);
        stage.setScene(scene);
        stage.setTitle("TableView 鼠标拖动多选单元格");
        stage.show();
    }

    // 工具：从鼠标位置推算出当前单元格位置
    private TablePosition<?, ?> getCellAtMouse(TableView<?> tableView, MouseEvent event) {
        for (TablePosition<?, ?> pos : tableView.getSelectionModel().getSelectedCells()) {
            TableColumn<?, ?> column = pos.getTableColumn();
            int rowIndex = pos.getRow();
            if (column != null && rowIndex >= 0) {
                return pos;
            }
        }
        return null;
    }

    public static class Person {
        private final SimpleStringProperty name;
        private final SimpleStringProperty age;
        private final SimpleStringProperty city;

        public Person(String name, String age, String city) {
            this.name = new SimpleStringProperty(name);
            this.age = new SimpleStringProperty(age);
            this.city = new SimpleStringProperty(city);
        }

        public SimpleStringProperty nameProperty() { return name; }
        public SimpleStringProperty ageProperty() { return age; }
        public SimpleStringProperty cityProperty() { return city; }
    }

    public static void main(String[] args) {
        launch(args);
    }
}